package com.css.fxfzypg.modules.earthquakedisasterloss.service.impl;

import com.css.fxfzypg.base.response.RestResponse;
import com.css.fxfzypg.constants.R;
import com.css.fxfzypg.modules.SettingSeismic.entity.SeismicIntensityRelation;
import com.css.fxfzypg.modules.SettingSeismic.repository.IntensityRelationRepository;
import com.css.fxfzypg.modules.earthquakedisasterloss.repository.SettingSeismicInfluencefliedRepository;
import com.css.fxfzypg.modules.earthquakedisasterloss.service.CountRescueForceService;
import com.css.fxfzypg.modules.earthquakedisasterloss.vo.SeismicInfluencefliedVO;
import com.css.fxfzypg.modules.model.entity.RescueForceEntity;
import com.css.fxfzypg.modules.model.service.RescueForceService;
import com.css.fxfzypg.modules.resultupload.repository.entity.ResultDetailsEntity;
import com.css.fxfzypg.modules.resultupload.repository.entity.ResultMainEntity;
import com.css.fxfzypg.modules.resultupload.service.ResultService;
import com.css.fxfzypg.modules.resultupload.service.ResultTotalService;
import com.css.fxfzypg.util.PlatformDateUtils;
import com.css.fxfzypg.util.PlatformObjectUtils;
import com.css.fxfzypg.util.PlatformSessionUtils;
import com.css.fxfzypg.util.ResponseCreator;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description: fxfzypg
 * @Author: lhl
 * @CreateDate: 2022/10/12 13:56
 */
@Service
public class CountRescueForceServiceImpl implements CountRescueForceService {

    @Resource
    RescueForceService rescueForceService;
    @Resource
    ResultTotalService resultTotalService;
    @Resource
    IntensityRelationRepository IntensityRelationRepository;
    @Resource
    private SettingSeismicInfluencefliedRepository settingSeismicInfluencefliedRepository;
    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public RestResponse countRescueForce(String taskId, String modelId) {
        RestResponse restResponse = null;
        try {
            if (PlatformObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(taskId))) {
                return RestResponse.fail(503, "该任务的正在被其他人计算，请稍后再操作！！！");
            }
            redisTemplate.opsForValue().set(taskId, "6-1");
            List<SeismicInfluencefliedVO> voList = settingSeismicInfluencefliedRepository.find3ByTaskId(taskId);
            if (voList.size() < 1) {
                return RestResponse.fail("请生成该任务下的地震影响场！");
            }
            Map<String, BigDecimal[]> detailsMap = new HashMap<>();
            BigDecimal[] details = null;
            ResultDetailsEntity d = null;
            //救援力量需求评估模型的id
            RescueForceEntity modelById = rescueForceService.getModelById(modelId);
            for (SeismicInfluencefliedVO s : voList) {
                String key1 = taskId + "-" + s.getFaultNum() + "-" + s.getEarthquakeLevel() + "-" + s.getAngle() + "-" + "2";
                if (d == null) {
                    d = resultTotalService.getResultDetailsEntity(taskId, s.getFaultNum(), s.getEarthquakeLevel(), s.getAngle());
                } else {
                    if (!key1.equals(taskId + "-" + d.getSort() + "-" + d.getMagnitude() +
                            "-" + d.getAngle() + "-" + "2")) {
                        d = resultTotalService.getResultDetailsEntity(taskId, s.getFaultNum(), s.getEarthquakeLevel(), s.getAngle());
                    }
                }
                if (PlatformObjectUtils.isEmpty(d)) {
                    continue;
                }
                BigDecimal R = new BigDecimal(d.getDisasterNum());//受灾人数（万人）
                BigDecimal M = d.getMagnitude();//震级

                //震级系数
                BigDecimal rescue_ranks_model_number1 = modelById.getRescueRanksModelNumber1();
                BigDecimal rescue_ranks_model_number2 = modelById.getRescueRanksModelNumber2();
                BigDecimal rescue_ranks_model_number3 = modelById.getRescueRanksModelNumber3();
                //模型公式：
                // 1、：以当地驻军和武警消防为主，基本无需外地救援队伍。
                // 2、：5<=M<6:Rr=R*0.009(0.008-0.01)
                // 3、：6<=M<7:Rr=R*0.008(0.005-0.01)
                // 4、：5<=M<6:Rr=R*0.04(0.03-0.05)
                // 5、无论震级多大，所需救援队伍人数上限值为20万人。
                // 参数说明：M--地震震级；Rr--救援需求人数（人）；R--受灾人数（人）

                //专业救援力量占比
                String major_rescue_force_proportion = modelById.getMajorRescueForceProportion();
                //民间救援力量占比
                String popular_rescue_force_proportion = modelById.getPopularRescueForceProportion();
                //社会其他力量占比
                String society_other_force_proportion = modelById.getSocietyOtherForceProportion();
                //6、其中专业救援力量占70%、民间救援力量20%、社会其他力量10%。
                //救援力量需求=灾区总人口 × 震级系数

                //需紧急救援力量
                BigDecimal Rr = BigDecimal.ZERO;
                if (M.compareTo(BigDecimal.valueOf(5)) > -1 && M.compareTo(BigDecimal.valueOf(6)) < 0) {
                    Rr = rescue_ranks_model_number1.multiply(R);
                } else if (M.compareTo(BigDecimal.valueOf(6)) > -1 && M.compareTo(BigDecimal.valueOf(7)) < 0) {
                    Rr = rescue_ranks_model_number2.multiply(R);
                } else if (M.compareTo(BigDecimal.valueOf(7)) > -1) {
                    Rr = rescue_ranks_model_number3.multiply(R);
                }

                //转换单位，从万人到人
                Rr = Rr.multiply(BigDecimal.valueOf(10000));
                //无论震级多大，所需救援队伍人数上限值为20万人。
                if (Rr.compareTo(BigDecimal.valueOf(200000)) > 0) {
                    Rr = BigDecimal.valueOf(200000);
                }
                //专业救援力量人数
                BigDecimal major_rescue_force = Rr.multiply(BigDecimal.valueOf(Long.parseLong(major_rescue_force_proportion) / 100.0)).setScale(0, RoundingMode.DOWN);
                //民间救援力量人数
                BigDecimal popular_rescue_force = Rr.multiply(BigDecimal.valueOf(Long.parseLong(popular_rescue_force_proportion) / 100.0)).setScale(0, RoundingMode.DOWN);
                //社会其他力量人数
                BigDecimal society_other_force = Rr.multiply(BigDecimal.valueOf(Long.parseLong(society_other_force_proportion) / 100.0)).setScale(0, RoundingMode.DOWN);

                //医务人员需求与救援人员需求成一定比例
                BigDecimal medical_staff_model_number = modelById.getMedicalStaffModelNumber();
                //医务人员分为医生、护士、心里医生。
                // 医务人员需求与救援人员需求成一定比例：
                //          Yd=Rr*0.06(0.05-0.1)
                // 参数说明：Yd--医务人员需求（人）；Rr--救援需求人数（人）
                String doctor_proportion = modelById.getDoctorProportion();
                String nurse_proportion = modelById.getNurseProportion();
                String psychologist_proportion = modelById.getPsychologistProportion();
                // 其中医生占30%、护士占65%、心理医生占5%
                //医务人员的人数
                BigDecimal yihu = Rr.multiply(medical_staff_model_number).setScale(0, RoundingMode.DOWN);
                //医生的人数
                BigDecimal doctor = yihu.multiply(BigDecimal.valueOf(Long.parseLong(doctor_proportion) / 100.0)).setScale(0, RoundingMode.DOWN);
                //护士的人数
                BigDecimal nurse = yihu.multiply(BigDecimal.valueOf(Long.parseLong(nurse_proportion) / 100.0)).setScale(0, RoundingMode.DOWN);
                //心理医生的人数w
                BigDecimal psychologist = yihu.multiply(BigDecimal.valueOf(Long.parseLong(psychologist_proportion) / 100.0)).setScale(0, RoundingMode.DOWN);

                if (detailsMap.containsKey(key1)) {
                    details = detailsMap.get(key1);
                    details[0] = details[0].add(Rr);
                    details[1] = details[1].add(major_rescue_force);
                    details[2] = details[2].add(popular_rescue_force);
                    details[3] = details[3].add(society_other_force);
                    details[4] = details[4].add(yihu);
                    details[5] = details[5].add(doctor);
                    details[6] = details[6].add(nurse);
                    details[7] = details[7].add(psychologist);
                } else {
                    details = new BigDecimal[8];
                    details[0] = Rr;
                    details[1] = major_rescue_force;
                    details[2] = popular_rescue_force;
                    details[3] = society_other_force;
                    details[4] = yihu;
                    details[5] = doctor;
                    details[6] = nurse;
                    details[7] = psychologist;
                }
                detailsMap.put(key1, details);
            }

            Map<String, ResultMainEntity> listMap = new HashMap<>();
            ResultMainEntity r = null;
            for (Map.Entry<String, BigDecimal[]> entry : detailsMap.entrySet()) {
                ResultDetailsEntity entity = new ResultDetailsEntity();
                String[] split = entry.getKey().split("-");
                entity.setTaskId(split[0]);
                entity.setSort(split[1]);
                entity.setMagnitude(new BigDecimal(split[2]));
                entity.setAngle(split[3]);

                BigDecimal[] value = entry.getValue();
                entity.setRescueForce(String.valueOf(value[0].intValue()));
                entity.setRescueForceZy(String.valueOf(value[1].intValue()));
                entity.setRescueForceMj(String.valueOf(value[2].intValue()));
                entity.setRescueForceQt(String.valueOf(value[3].intValue()));
                entity.setMedicalMatters(String.valueOf(value[4].intValue()));
                entity.setMedicalNum(String.valueOf(value[5].intValue()));
                entity.setNurseNum(String.valueOf(value[6].intValue()));
                entity.setPsychologist(String.valueOf(value[7].intValue()));

                entity.setUpdateId(PlatformSessionUtils.getUserId());
                entity.setUpdateTime(PlatformDateUtils.getCurrentTimestamp());
                entity.setDataSource("2");
                resultTotalService.updateResultDetailsEntity(entity);

                String key = taskId + "-" + entity.getSort() + "-" + entity.getMagnitude() + "-" + "2";
                if (listMap.containsKey(key)) {
                    r = listMap.get(key);
                    r.setRescueForceBefore(compareTo(value[0], r.getRescueForceBefore()));
                    r.setRescueForceZyBefore(compareTo(value[1], r.getRescueForceZyBefore()));
                    r.setRescueForceMjBefore(compareTo(value[2], r.getRescueForceMjBefore()));
                    r.setRescueForceQtBefore(compareTo(value[3], r.getRescueForceQtBefore()));
                    r.setMedicalMattersBefore(compareTo(value[4], r.getMedicalMattersBefore()));
                    r.setMedicalNumBefore(compareTo(value[5], r.getMedicalNumBefore()));
                    r.setNurseNumBefore(compareTo(value[6], r.getNurseNumBefore()));
                    r.setPsychologistBefore(compareTo(value[7], r.getPsychologistBefore()));
                } else {
                    r = new ResultMainEntity();
                    r.setRescueForceBefore(value[0].intValue() + "-0");
                    r.setRescueForceZyBefore(value[1].intValue() + "-0");
                    r.setRescueForceMjBefore(value[2].intValue() + "-0");
                    r.setRescueForceQtBefore(value[3].intValue() + "-0");
                    r.setMedicalMattersBefore(value[4].intValue() + "-0");
                    r.setMedicalNumBefore(value[5].intValue() + "-0");
                    r.setNurseNumBefore(value[6].intValue() + "-0");
                    r.setPsychologistBefore(value[7].intValue() + "-0");
                }
                listMap.put(key, r);
            }
            resultTotalService.updateResultMainEntity(listMap, "2");

            SeismicIntensityRelation byTaskId = IntensityRelationRepository.getByTaskId(taskId);
            byTaskId.setModel5Id(modelId);
            byTaskId.setExtends1("1");
            byTaskId.setButton5_status1("1");
            IntensityRelationRepository.updateSeismicIntensityRelation(byTaskId);

            return ResponseCreator.createSuccessResponse(null, "计算成功!");
        } catch (Exception e) {
            e.printStackTrace();
            restResponse = RestResponse.fail("计算失败!");
            return restResponse;
        } finally {
            redisTemplate.delete(taskId);
            if (restResponse != null) {
                if (restResponse.getCode() != 200) {
                    //事务手动回滚
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                }
            }
        }
    }

    private String compareTo(BigDecimal num1, String num2) {
        // num1:5 8 4
        // num2:10-0
        String[] split = num2.split("-");//5 10
        for (int i = 0; i < split.length; i++) {
            if (i == 0 && num1.compareTo(new BigDecimal(split[0])) < 0) {
                if (split.length == 2) {
                    if (new BigDecimal(split[0]).compareTo(new BigDecimal(split[1])) > 0) {
                        split[1] = String.valueOf(new BigDecimal(split[0]).intValue());
                        split[0] = String.valueOf(num1.intValue());
                    } else {
                        split[0] = String.valueOf(num1.intValue());
                        split[1] = String.valueOf(new BigDecimal(split[1]).intValue());
                    }
                } else {
                    split[0] = String.valueOf(num1.intValue());
                    split[1] = String.valueOf(new BigDecimal(split[1]).intValue());
                }
            } else if (i == 1 && num1.compareTo(new BigDecimal(split[1])) > 0) {
                split[0] = String.valueOf(new BigDecimal(split[0]).intValue());
                split[1] = String.valueOf(num1.intValue());
            }
        }
        num2 = split[0] + "-" + split[1];
        return num2;
    }
}
